home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Disc to the Future 2
/
Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin
/
MAC
/
MACSHELL
/
MS1
/
SHELL_SO
/
SCRIPT.C
< prev
next >
Wrap
Text File
|
1992-12-02
|
19KB
|
789 lines
/*
* MacShell Source File
*
* Copyright (c) 1989, 1990, 1991, 1992 Suick Bay Technologies. All rights reserved.
*
*
* RESTRICTIONS ON MacShell program and source code.
*
* Ñ╩MacShell¬ is a product of Suick Bay Technologies and is provided for
* restricted use by the owner of the CDROM "Disk to the future II".
*
* Ñ╩No permission is granted for any commercial use without the written
* consent of the Suick Bay Technologies.
*
* Ñ╩No permission is granted for any redistribution of any kind use without
* the written consent of the Suick Bay Technologies.
*
* Ñ╩Permission is granted to use this for any personal noncommercial use.
*
* Ñ╩You may not distribute source or executable code at all, nor may you
* distribute it with or within a commercial product without the written
* consent of the Suick Bay Technologies. Please send modifications to
* the author for inclusion in updates to the program. Thanks.
*
*
* MacShell¬ IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
* WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
* PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
*
* SUICK BAY TECHNOLOGIES SHALL HAVE NO LIABILITY WITH RESPECT TO THE
* INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY MACSHELL
* OR ANY PART THEREOF.
*
* In no event will Suick Bay Technologies be liable for any lost revenue
* or profits or other special, indirect and consequential damages, even if
* Suick Bay Technologies has been advised of the possibility of such damages.
*
* Suick Bay Technologies can be reached at:
*
* 8768 Cottonwood lane
* Maple Grove, MN 55369
* Voice: (612) 425-7025
* AppleLink: D5233
*
*
* No parts of this software may be reproduced or stored in a
* retrieval system or transmitted in any form, or any means,
* electronic, mechanical, photocopying, recording or otherwise,
* without the prior written permission of Suick Bay Technologies.
*
* Spread the word and not the disk.
*
* SPK 012290 : Initial
*/
/*******************************************************************
*
* Script control file
*
Before a command is executed the following substitutions occur
Ñ Parameter substitution (shell vars)
Ñ Command 'Quote' substitution ('pwd')
Ñ Blank interpretation
Ñ File name generation (*?[╔])
Shell vars
$? Exit status (return code) of the last command
$# number of parameters (arguments)
$$ Process number of this shell
$0 The name of the command procedure being executed
$1 argument 1
$2 argument 2
$3 argument 3 ... etc.
Control Flow
while command-list
do command-list
done
until command-list
do command-list
done
if command-list
then command-list
[ elif command-list then command-list ]
[ else command-list ]
fi
break Exit from enclosing for or while loop
continue do next iteration of for or while
*******************************************************************/
#define _SCRIPTDEBUG
#define _SDB
#include "System.h"
#include "Parse.h"
#include "Proc.h"
#include "Path.h"
#include "Shell.h"
static Boolean verbose; /* echo commands as they are executed in the script */
extern Boolean StdOutAppend; /* flag for appending std out file */
/*******************************************************************/
Boolean DoSCRIPTLine( WHandle ShellWh, int16 ProcID, char *string )
{
char *cp, buf[ 64 ], stdInFile[ 64 ], stdOutFile[ 64 ];
int16 currProcSlot, lastProcSlot, pipeFromLast, pipeToNext, pipeErr,
i, ioOk, err,
cmdc,
tokenType, lastToken,
ProcDataAvail,
parseErr = 0,
inProc, outProc, errProc;
ShellWindRec **MyShell;
/*
* Command execution vars
*/
ProcPtr theCommand;
int16 needsStdIn;
if( UserAbort() )
return( FALSE );
MyShell = (ShellWindRec **) (**ShellWh).thing;
lastProcSlot = CL_PROCID;
if( ShellWh && string )
{
cp = string;
#ifdef SCRIPTDEBUG
printf( "DoSCRIPTLine : '%s'\n", string );
#endif
currProcSlot = GetProcSlot( ShellWh );
if( currProcSlot == UNKNOWN )
{
ShellError( se_noProcSlots );
return( FALSE );
}
else /* Initialize the Proc */
{
(**MyShell).Proc[ currProcSlot ].argc = 0;
cmdc = 0;
(**MyShell).StdOutAppend = FALSE;
lastToken = UNKNOWN;
ProcDataAvail = FALSE;
lastProcSlot = ProcID;
pipeFromLast = FALSE;
pipeToNext = FALSE;
pipeErr = FALSE;
ioOk = FALSE;
stdInFile[ 0 ] = '\0';
stdOutFile[ 0 ] = '\0';
}
inProc = STDIN_PROCID;
outProc = (**MyShell).Proc[ ProcID ].StdOutProcID;
errProc = (**MyShell).Proc[ ProcID ].StdErrProcID;
while( cp && !UserAbort() )
{
cp = GetShellToken( cp, buf, &tokenType );
parseErr = 0;
CursorWait();
switch( tokenType )
{
case tkn_andf : /* '&&' */
case tkn_orf : /* '||' */
case tkn_background : /* '&' */
break;
case tkn_pipeOutErr : /* '|&' */
pipeErr = TRUE;
case tkn_pipe : /* '|' */
pipeToNext = TRUE;
case tkn_separator : /* ';' */
case tkn_eol :
Execute:
if( tokenType == tkn_eol && verbose )
procPrintf( ShellWh, ProcID, "%s%s",
ShellGetVar( ShellWh, "PS1" ), string );
if( ProcDataAvail )
{
/* Start the process
*/ char command[ 256 ];
GetArgv( ShellWh, currProcSlot, 0, command );
if( GetCommandInfo( command, &theCommand, &needsStdIn ) )
{
forceCommand :
ShellSetVar( ShellWh, "COMMAND", string );
(**MyShell).Proc[ currProcSlot ].CmdProcPtr = theCommand;
/* create input proc */
if( *stdInFile && needsStdIn ) /* init stdin */
{
(**MyShell).Proc[ currProcSlot ].ProcActive = TRUE;
inProc = GetProcSlot( ShellWh );
(**MyShell).Proc[ currProcSlot ].ProcActive = FALSE;
(**MyShell).Proc[ inProc ].argc = 0;
if( inProc == UNKNOWN ) /* no slots left !!! */
{
ShellError( se_noProcSlots );
return( FALSE );
}
(**MyShell).Proc[ inProc ].CmdProcPtr = (ProcPtr) StdInProc;
ioOk = (*StdInProc)( PROC_INIT, ShellWh, inProc, stdInFile );
if( ioOk == FALSE )
parseErr = se_ioRedir;
else
(**MyShell).Proc[ inProc ].ProcActive = TRUE;
}
/* create output proc */
if( *stdOutFile ) /* init stdout */
{
(**MyShell).Proc[ currProcSlot ].ProcActive = TRUE;
outProc = GetProcSlot( ShellWh );
(**MyShell).Proc[ currProcSlot ].ProcActive = FALSE;
(**MyShell).Proc[ outProc ].argc = 0;
if( outProc == UNKNOWN ) /* no slots left !!! */
{
ShellError( se_noProcSlots );
return( FALSE );
}
(**MyShell).Proc[ outProc ].CmdProcPtr = (ProcPtr) StdOutProc;
ioOk = (*StdOutProc)( PROC_INIT, ShellWh, outProc, stdOutFile );
if( ioOk == FALSE )
parseErr = se_ioRedir;
else
(**MyShell).Proc[ outProc ].ProcActive = TRUE;
}
if( pipeFromLast && (lastProcSlot != CL_PROCID))
InitProc( ShellWh, currProcSlot, lastProcSlot, outProc, errProc );
else
{
InitProc( ShellWh, currProcSlot, inProc, outProc, errProc );
if( needsStdIn && (parseErr == noErr))
(**MyShell).prompt = 1;
}
if( tokenType == tkn_separator )
{
/* command was separated on the command line
run the command until it is complete */
while( (**MyShell).Proc[ currProcSlot ].ProcActive )
ProcMgrIdle( ShellWh );
outProc = (**MyShell).Proc[ ProcID ].StdOutProcID;
errProc = (**MyShell).Proc[ ProcID ].StdErrProcID;
}
/* Set up another proc slot */
lastProcSlot = currProcSlot;
ProcDataAvail = FALSE;
pipeFromLast = pipeToNext;
currProcSlot = GetProcSlot( ShellWh );
if( currProcSlot == UNKNOWN )
{
ShellError( se_noProcSlots );
return( FALSE );
}
else /* Initialize the Proc */
{
(**MyShell).Proc[ currProcSlot ].argc = 0;
cmdc = 0;
stdInFile[ 0 ] = '\0';
stdOutFile[ 0 ] = '\0';
ProcDataAvail = FALSE;
(**MyShell).StdOutAppend = FALSE;
if( tokenType == tkn_separator )
{
lastProcSlot = CL_PROCID;
pipeFromLast = FALSE;
pipeToNext = FALSE;
pipeErr = FALSE;
}
}
}
else if( BuiltInCMD( ShellWh, currProcSlot, ProcID, command ))
{
/* taken care of */
}
else /* name could be a script or an application */
{
int16 refNum;
char str[ 256 ];
strcpy( str, command );
CtoPstr( str );
refNum = OpenFile( ShellWh, command, 'TEXT', fsRdPerm );
if( !refNum )
{
strcpy( str, command );
strcat( str, ".script" );
refNum = OpenFile( ShellWh, str, 'TEXT', fsRdPerm );
if( refNum )
strcpy( command, str );
}
if( refNum )
{
int16 ni, na, nc = 0;
char *cp, *np;
FSClose( refNum );
/* save the new command and arguments */
na = (**MyShell).Proc[ currProcSlot ].argc;
(**MyShell).Proc[ currProcSlot ].argv[ 0 ] = 0;
cp = command;
while( *cp++ )
nc++;
nc++;
for( ni = 1; ni < na; ni++ )
{
GetArgv( ShellWh, currProcSlot, ni, str );
(**MyShell).Proc[currProcSlot].argv[ni] = nc;
np = str;
while( *cp++ = *np++ )
nc++;
nc++;
}
for( ni = 0; ni < nc; ni++ )
(**MyShell).Proc[ currProcSlot ].cmdline[ni] = command[ni];
theCommand = (ProcPtr) DoSCRIPT;
needsStdIn = FALSE;
goto forceCommand;
}
else
{
refNum = OpenFile( ShellWh, command, 'APPL', fsRdPerm );
if( refNum )
{
pathType pt;
OsErr lerr;
FSClose( refNum );
/* application */
if( CanLaunch() == FALSE )
{
procPrintf( ShellWh, ProcID,
"sh : Applications can only be launched under MultiFinder\n" );
}
else
{
pt = SetCurrPath( command );
if( pt == pathIsFile )
{
int16 cv;
int32 cd, cp;
GetPWDInfo( &cv, &cd, &cp );
strcpy( str, GetLastScan() );
CtoPstr( str );
lerr = DoLaunch( str, cv, cd );
if( lerr )
procPrintf( ShellWh, ProcID,
"sh : can't launch %ps (%d)\n", str, lerr );
}
}
ResetShellPWD( ShellWh );
}
else
{
char *sp, *cp;
sp = cp = command;
while( *cp )
{
if( *cp == '=' )
break;
else
cp++;
}
if( *cp == '=' ) /* Shell variable, put '\0' over '=' */
{
*cp++ = '\0';
ShellSetVar( ShellWh, sp, cp );
}
else
parseErr = se_unknownCmd;
}
}
}
}
break;
case tkn_var : /* '$' */
case tkn_identifier : /* */
case tkn_digit : /* '0-9.' */
{
char *s;
char varName[ 64 ];
/* save as argument */
if( tokenType == tkn_var )
{
if( cp )
{
cp = GetShellToken( cp, varName, &tokenType );
s = ShellGetVar( ShellWh, varName );
}
else
s = buf;
}
else
s = buf;
(**MyShell).Proc[currProcSlot].argv[(**MyShell).Proc[currProcSlot].argc] =
cmdc;
while ( (**MyShell).Proc[currProcSlot].cmdline[cmdc++] = *s++ );
(**MyShell).Proc[currProcSlot].argc++;
ProcDataAvail = TRUE;
}
break;
case tkn_inputRedirect: /* '<' */
if( cp )
{
cp = GetShellToken( cp, stdInFile, &tokenType );
if( tokenType != tkn_identifier )
parseErr = se_expectFile;
}
else
parseErr = se_expectFile;
break;
case tkn_inputFromHere: /* '<<' */
break;
case tkn_outputAppend: /* '>>' */
(**MyShell).StdOutAppend = TRUE;
case tkn_outputRedirect: /* '>' */
if( cp )
{
cp = GetShellToken( cp, stdOutFile, &tokenType );
if( tokenType != tkn_identifier )
parseErr = se_expectFile;
}
else
parseErr = se_expectFile;
break;
case tkn_comment : /* '#' */
{
while( cp )
{
cp = GetShellToken( cp, stdOutFile, &tokenType );
if( tokenType == tkn_eol )
break;
}
goto Execute;
}
break;
case tkn_caseDelimit : /* ';;' */
case tkn_leftParen : /* '(' */
case tkn_rightParen : /* ')' */
case tkn_singleQuote : /* ''' */
case tkn_doubleQuote : /* '"' */
case tkn_if : /* 'if' */
case tkn_then : /* 'then' */
case tkn_else : /* 'else' */
case tkn_elif : /* 'elif' */
case tkn_fi : /* 'fi' */
case tkn_case : /* 'case' */
case tkn_in : /* 'in' */
case tkn_esac : /* 'esac' */
case tkn_for : /* 'for' */
case tkn_while : /* 'while' */
case tkn_until : /* 'until' */
case tkn_do : /* 'do' */
case tkn_done : /* 'done' */
case tkn_break : /* 'break' */
case tkn_continue : /* 'continue' */
case tkn_exit : /* 'exit' */
case tkn_leftCurl : /* '{' */
case tkn_rightCurl : /* '}' */
break;
case tkn_unknown :
break;
default :
break;
}
if( parseErr )
break;
}
lastToken = tokenType;
}
/*
* Start execution of any commands
*/
if( parseErr && verbose )
{
/* printf( "%s", (**MyShell).Proc[ currProcSlot ].cmdline ); */
ShellError( parseErr );
}
if( lastProcSlot != CL_PROCID )
ProcMgrIdle( ShellWh );
return( TRUE );
}
/*******************************************************************/
void SCRIPTCallBack( WHandle ShellWh, int16 ProcID,
char *path, char *last,
pathType what, int16 vRefNum, int32 dirID )
{
CInfoPBRec pb;
char str[ 256 ];
int16 sRefNum, sErr = noErr, i, argc;
int32 count;
char *cp;
ShellWindRec **MyShell = (ShellWindRec **) (**ShellWh).thing;
argc = (**MyShell).Proc[ ProcID ].argc;
if( what != pathIsFile )
return;
strcpy( str, last );
CtoPstr( str );
pb.hFileInfo.ioCompletion = NULL;
pb.hFileInfo.ioNamePtr = (StringPtr) str;
pb.hFileInfo.ioVRefNum = vRefNum;
pb.hFileInfo.ioDirID = dirID;
pb.hFileInfo.ioFDirIndex = 0;
sErr = PBHGetFInfo( &pb, FALSE );
#ifdef SDB
printf( "Script GetInfo Type %lX\n", pb.hFileInfo.ioFlFndrInfo.fdType );
#endif
if( sErr || pb.hFileInfo.ioFlFndrInfo.fdType != 'TEXT' )
return;
sErr = HOpen( vRefNum, dirID, str, fsRdPerm, &sRefNum );
PtoCstr( str );
#ifdef SDB
printf( "Script OpenFile %d\n", sRefNum );
#endif
if( !sErr && sRefNum )
{
#ifdef SCRIPTDEBUG
printf( "Running SCRIPT : '%s'\n", str );
#endif
i = 0;
cp = str;
while( !sErr && i < 255 )
{
count = 1L;
sErr = FSRead( sRefNum, &count, cp );
if( !sErr || sErr == eofErr )
{
if( sErr == eofErr )
*cp = '\n';
if( *cp == '\r' )
*cp = '\n';
if( *cp == '\n' || sErr == eofErr )
{
*++cp = '\0';
if( DoSCRIPTLine( ShellWh, ProcID, str ) == FALSE )
return;
i = 0;
cp = str;
}
else if( *cp == '$' ) /* shell var ? */
{
sErr = FSRead( sRefNum, &count, cp );
if( (*cp >= '0') && (*cp <= '9') ) /* substitute the shell var */
{
int16 argc;
char *sp, argbuf[ 256 ];
argc = *cp - '0';
if( argc < (**MyShell).Proc[ ProcID ].argc )
{
GetArgv( ShellWh, ProcID, argc, argbuf );
sp = argbuf;
while( *sp )
{
*cp = *sp;
cp++;
sp++;
i++;
}
}
}
else if( *cp == '#' ) /* number of arguments */
{
*cp++ = '0' + argc;
}
else /* oops, add the char and continue */
{
char cs = *cp;
cp--;
*cp++ = '$';
*cp++ = cs;
i+=2;
}
}
else
{
cp++;
i++;
}
}
}
FSClose( sRefNum );
}
}
/*******************************************************************/
void SCRIPTFile( WHandle ShellWh, int16 ProcID, char *argument )
{
ShellWindRec **MyShell;
MyShell = (ShellWindRec **) (**ShellWh).thing;
#ifdef SDB
printf( "Script ExpandPath %s\n", argument );
#endif
ScanInit();
ScanForTYPE( 'TEXT' );
ExpandPath( ShellWh, ProcID, argument, (ProcPtr) SCRIPTCallBack,
(**MyShell).pwdVRefNum, (**MyShell).pwdDirID );
ScanInit();
ResetShellPWD( ShellWh );
}
/*******************************************************************/
Boolean DoSCRIPT( int16 ProcToken, WHandle ShellWh,
int16 ProcID, char *string )
{
int16 i, argc;
char *cp, argument[ 256 ];
ShellWindRec **MyShell = (ShellWindRec **) (**ShellWh).thing;
switch( ProcToken )
{
case PROC_INIT :
(**MyShell).Proc[ ProcID ].flags = TRUE;
break;
case PROC_TERM :
case PROC_BREAK :
/* Tell the shell that we're done */
SendOutToken( ShellWh, ProcID, PROC_BREAK );
/* Turn ourself off */
(**MyShell).Proc[ ProcID ].ProcActive = FALSE;
break;
case PROC_STDIN :
if( (**MyShell).Proc[ ProcID ].flags )
{
(**MyShell).Proc[ ProcID ].flags = FALSE;
/* get arguments */
argc = (**MyShell).Proc[ ProcID ].argc;
verbose = FALSE;
#ifdef SCRIPTDEBUG
verbose = TRUE;
#endif
for( i = 1; i < argc; i++ )
{
GetArgv( ShellWh, ProcID, i, argument );
cp = argument;
if( *cp++ == '-' )
while( *cp )
switch( *cp++ )
{
case 'v' : /* verbose */
verbose = TRUE;
break;
case 'e' : /* exit if a command fails */
break;
case 'n' : /* read commands without executing them */
break;
case 's' : /* s read from stdin */
break;
case 't' : /* read and execute one command then exit */
break;
case 'x' : /* print commands as executed, with arguments */
break;
}
}
for( i = 0; i < argc; i++ )
{
GetArgv( ShellWh, ProcID, i, argument );
if( i == 0 && strcmp( argument, "script" ) == 0 )
continue;
if( *argument != '-' )
SCRIPTFile( ShellWh, ProcID, argument );
}
/* Tell the shell that we're done */
SendOutToken( ShellWh, ProcID, PROC_BREAK );
/* Turn ourself off */
(**MyShell).Proc[ ProcID ].ProcActive = FALSE;
}
return( FALSE );
}
}